package dk;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Scanner;
import java.util.TimeZone;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class util {


			// Loop through all of the created files and build their file information
			public void buildfileInfoContents(String inputlocation, String outputlocation, List<fileInfo> filelist){
				
				int tempsize;
				for (int i = 0; i<filelist.size(); i++){
					tempsize = getFileLineCount(inputlocation + filelist.get(i).getFileName());
					System.out.println("Adding line contents for: " + inputlocation + filelist.get(i).getFileName());
					
					// it takes longer to do this, but lines have to be cleaned on a line by line basis.
					for(int b = 0; b < tempsize; b++){
						filelist.get(i).addFileContents(Readfile(inputlocation + filelist.get(i).getFileName(),b));				
					}
					
					
				// now test showing the contents
					createOutputFile(outputlocation + filelist.get(i).getFileName(),filelist.get(i).getAllCleanFileContents());
				}	
			}
			
			
			// Older and slower method, but needed for "cleaning"
			public String Readfile(String location, int lineNumber){

			    FileInputStream fis = null;
			    BufferedReader reader = null;
			    String retVal = null;
			  
			    try {
			        fis = new FileInputStream(location);
			        reader = new BufferedReader(new InputStreamReader(fis));
			      
			        String line = reader.readLine();
			        int count = 0;
			        while(line != null){
			          //  System.out.println(line);
			        	if(count==lineNumber){
			        		retVal = line;
			        	}
			        	line = reader.readLine();
			            count++;
			        }           
			      
			    } catch (FileNotFoundException ex) {
			    //    Logger.getLogger(BufferedReaderExample.class.getName()).log(Level.SEVERE, null, ex);
			    } catch (IOException ex) {
			   //     Logger.getLogger(BufferedReaderExample.class.getName()).log(Level.SEVERE, null, ex);
			      
			    } finally {
			        try {
			            reader.close();
			            fis.close();
			        } catch (IOException ex) {
			        //    Logger.getLogger(BufferedReaderExample.class.getName()).log(Level.SEVERE, null, ex);
			        }
			    }
			    return retVal;
		} 

			

			
			// 1) Get list of all relevant files
			public List<fileInfo> buildfileInfoList(String inputlocation){
				List<fileInfo> fileinfolist=new ArrayList<fileInfo>();	
				  String files;
				  File folder = new File(inputlocation);
				  File[] listOfFiles = folder.listFiles(); 
				 
				  for (int i = 0; i < listOfFiles.length; i++) {
				 
				   if (listOfFiles[i].isFile()) {
				   files = listOfFiles[i].getName();
				   	//	if (files.endsWith("cil.i")){{
				   if (files.endsWith("cil.c") && (!files.startsWith("."))){{
				      //    System.out.println(files);
				   			fileinfolist.add(new fileInfo(files));
				        }
				     }
				
				
				   }
				}
				  return fileinfolist;
			}

			
		// Build the list of files that shall be scanned for reporting purposes.
		public List<fileInfo> buildReportfileInfoList(String inputlocation){
			  
			
			// make sure that methodoutput exists
			// Might be a good idea to create the file if it does not exist
			
			
			List<fileInfo> fileinfolist=new ArrayList<fileInfo>();	
			
			  String files;
			  File folder = new File(inputlocation);
			  File[] listOfFiles = folder.listFiles(); 
			 
			  for (int i = 0; i < listOfFiles.length; i++) {
			 
			   if (listOfFiles[i].isFile()) {
				   files = listOfFiles[i].getName();
				   if(isExcludeReportScanFile(files)==false){
					   //System.out.println(files);
					   	fileinfolist.add(new fileInfo(files));
					   }
				   }
			   }
			  return fileinfolist;
			}

			// Determine if file should be excluded from the report scan
			private boolean isExcludeReportScanFile(String fileName){
				boolean retVal = false;
				if(fileName.toLowerCase().contains(".ds_store")){
					retVal = true;
				}
				
				return retVal;
			}
			
			
			public int getFileLineCount(String fileName){
				File file = new File(fileName);
		        Scanner scanner = null;
				try {
					scanner = new Scanner(file);
				} catch (FileNotFoundException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
		        int count = 0;
		        while (scanner.hasNextLine()) {
		                String line = scanner.nextLine();
		                count++;
		        }
		        return count;
			}
			
			
			public String getLineInformation(File file, int lineNumber){
				// This is all a pretty inneficient way to compare the files.
				//		This can be enchanced.
				String line = "";
		        int lineNo;
		        try {
		                FileReader fr = new FileReader(file);
		                BufferedReader br = new BufferedReader(fr);
		                for (lineNo = 1; lineNo < 99999; lineNo++) {
		                        if (lineNo == lineNumber) {
		                                line = br.readLine();
		                        } else
		                                br.readLine();
		                }
		        } catch (IOException e) {
		                e.printStackTrace();
		        }
		        
		        // if the line does not exist, just make it ""
		        // This will help in the line total calculation values.
		        if(line==null || line.equals("")){
		        	line="";
		       }
			return line;
			}	



		// output the contents of a file object to a physical file
			public void createOutputFile(String FileName, String fileContents){
				
				// Build a stringbuilder if I have to.
				
			     try{
			 		// Create file 
			 		FileWriter fstream = new FileWriter(FileName+".txt");
			         BufferedWriter out = new BufferedWriter(fstream);
			 		out.write(fileContents);
			 		//Close the output stream
			 		out.close();
			 		}catch (Exception e){//Catch exception if any
			 			System.err.println("Error: " + e.getMessage());
			 		}
			 	}
				



		// Retrieve the method name from a line of concolic output
		public String getMethodName(String input){
			String retVal="";

			if ((input.contains("^^efn^^") && (input.contains("^^sfn^^:")))){
				// create it as a string in case I want to output it for debugging purposes.
				final String tmpMethodName =input.substring(input.indexOf("^^sfn^^:")+8, input.indexOf("^^efn^^")).replace(" ", "");

				// Splitting the values is just a patch, it should be fixed in the crest script in linux.
				retVal = splitStringInHalf(tmpMethodName);
				//System.out.println("here" + retVal);

			}
			return retVal;
		}

		

		// Simple reverse string function
		public String reverseString(String s) {
			StringBuilder sb = new StringBuilder();
			for(int i = s.length() - 1; i >= 0; --i)
				sb.append(s.charAt(i));
				return sb.toString();
			}
			
			
		// Utility write file function
		public void WriteFile(String fileName, String Location,String Contents, boolean isAppend) {
			FileWriter out;
			try {
				out = new FileWriter(Location+"/"+ fileName, isAppend);
				out.write(Contents);
				out.close();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}	
			
		}	
		
		
				
		public int getMinLineCount(File file1, File file2){
			int retVal=0;
			int file1Count = getFileLineCount(file1); 
			int file2Count = getFileLineCount(file2); // assign these values so they only have to be called once
			if (file1Count <= file2Count){
				retVal = file1Count;
			}else{
				retVal = file2Count;
			}
			return retVal;
		}
		
		public int getFileLineCount(File file){
	        Scanner scanner = null;
			try {
				scanner = new Scanner(file);
			} catch (FileNotFoundException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
	        int count = 0;
	        while (scanner.hasNextLine()) {
	                String line = scanner.nextLine();
	                count++;
	        }
	        return count;
		}
		
		
		private boolean isUnix(){
			boolean retVal = true;
			if (System.getProperty("os.name").startsWith("Windows")) {
				retVal=false;
		    }
			return retVal;
		}
		
		
		public double roundTwoDecimals(double d) {
            DecimalFormat twoDForm = new DecimalFormat("#.##");
            return Double.valueOf(twoDForm.format(d));
		}
		
		
		// Only run this on line #2 - The method name needs to be passed to the file, but should be removed for comparision purposes.
		public String removeMethodNameFromLine(String input){
			return input.replace(getMethodName(input), "");
		}
		
		
		/*
		// Newer, faster version of reading in files.
		// Think about adding in check to remove the function name from string comparisions
		public String readDoc(String inputFile) {
			File f = new File(inputFile);
		    String text = "";
		    int read, N = 1024 * 1024;
		    char[] buffer = new char[N];

		    try {
		        FileReader fr = new FileReader(f);
		        BufferedReader br = new BufferedReader(fr);

		        while(true) {
		            read = br.read(buffer, 0, N);
		            text += new String(buffer, 0, read);

		            if(read < N) {
		                break;
		            }
		        }
		    } catch(Exception ex) {
		        ex.printStackTrace();
		    }

		    return text;
		}
		*/
		
		// Ian's new version
		public String readDoc(String inputFile) throws IOException {
			BufferedReader br = new BufferedReader(new FileReader(inputFile));
			StringBuilder text = new StringBuilder();
            String line = "";
            try{
            	line = br.readLine();
		
            	while(line != null){
            		text.append(line);
            		text.append("\n"); //added this line to fix comparision problem
            		line = br.readLine();
            	}
            }catch (Exception e){
            	e.printStackTrace();
            }finally{
            	br.close();
            	}
            return text.toString();
		}
		
		
		
		// Remove the contents of a folder
		public void clearFolder(String folder){
			File file = new File(folder);        
	        String[] myFiles;      
	            if(file.isDirectory()){  
	                myFiles = file.list();  
	                for (int i=0; i<myFiles.length; i++) {  
	                    File myFile = new File(file, myFiles[i]);   
	                    myFile.delete();  
	                }  
	             }  
		}
		
		
		// Return only the filename from the input path
		public String getFileNameFromInputPath(String input){
			String temp;	
			temp = reverseString(input);
			return reverseString(temp.substring(0, temp.indexOf(getFolderVal())));
		}
		
		// Alterate the switching value based on windows vs. Unix		
		private String getFolderVal(){
			String sepVal="";			
			if (isUnix()){
				// Unix
				sepVal = "/";
			}else{
				// WIN /
				sepVal = "\\";
			}
			return sepVal;
		}
		
		
		// Split up the contents of a duplicated string
		// This is just a patch, should probably be fixed in the crest code.
		public String splitStringInHalf(String input){
			String retVal="";
			if(input.length()%2==0){ // check to make sure that it is an even number
				retVal=input.substring(0,input.length()/2);
			}
			
			return retVal;
		}
		
		
		// Delete a directory
		private void deleteDir(File f) {
			if (f.isDirectory()) {
				for (File c : f.listFiles())
					deleteDir(c);
				}
			if (!f.delete()){
				//  throw new FileNotFoundException("Failed to delete file: " + f);
				System.out.println("Failed to delete file: " + f);
				}
			}
				
		// Remove duplicate items from a list
		// Note: The ordering will be destroyed
		public List<String> removeRepeatedListItems(List<String> inputList){
				// Usage: stringlist = removeRepeatedArrayListItems(stringlist);	
				ArrayList al = new ArrayList();
				// add elements to al, including duplicates
				HashSet hs = new HashSet();
				hs.addAll(inputList);
				inputList.clear();
				inputList.addAll(hs);
				return inputList;	
			}
		
		
		// Remove all the "counter" values from a line
		public String removeCounterValues(String line){
		
			StringBuilder sb = new StringBuilder();
			String myArray[] = line.split("\\&\\*\\&");
			for(int a = 1; a< line.split("\\&\\*\\&").length; a++){
				sb.append(myArray[a].toString().replaceAll("[0-9]", ""));
			}
			
			
			return sb.toString();
		
}
		
		
		// prepare a file path for reporting purposes
		public String convertRawMethodToReportFriendly(String input){
			String retVal="";
			
			if(input.length() > 0){
				retVal = input.replace("/", ".");
			}
			
			return retVal;
		}
		
		// httpd-2.2.14_copy.srclib.apr.test.abts.c
		
		// This should probably be renamed
		// Remove the method name from a specified input path
		public String RemoveMethodNameFromPath(String input){
			String retVal="";
			
			if(input.contains(".c")){
				// Reverse string
				// remove everything to right of first "." (2x)
				retVal = reverseString(input);
				retVal = retVal.substring(retVal.indexOf("."),retVal.length());
				retVal = retVal.substring(retVal.indexOf(".")+1,retVal.length());
				retVal = reverseString(retVal);
				// Reverse the string
			}
			
			
			return retVal;
		}
		
		
		// Remove the method name from a specified input path
		public String RemoveFileNameFromPath(String input, String bleh){
			File f = new File(input);
			return f.getParent();
		}
		
		
		
		// Determine if an item exists in an array
		public boolean isItemInArray(List<String> list, String searchInput){
			boolean retVal=false;
			  for (int i = 0; i < list.size(); i++) {
				  if(list.get(i).toString().equals(searchInput)){
					  retVal=true;
				  }
			  }
			return retVal;
		}

		
		// create directory if it does not exist
		public void createDirIfNotExist(String dir){
			System.out.println("create dir" + dir);
			File f = new File(dir); 
			if (!f.isDirectory()) {
				System.out.println("Creating directory: " + dir);
				f.mkdirs();
			}
		}
		
		
		
		// Create a directory if it does not exist. If it does, then clear it.
		public void createAndClearDir(String dir){
			File f = new File(dir); 
			if (!f.isDirectory()) {
				System.out.println("Creating directory: " + dir);
				f.mkdirs();
			}else{
				// if it does exist, then clear it
				System.out.println("Clearing directory: " + dir);
				deleteDir(f);
				f.mkdir();
			}
		}
		
		// Determine if a directory exists
		public boolean isDirectoryExist(String directoryName){
			File f = new File(directoryName); 
			if (!f.isDirectory()) {
				return false;
			}else{
				return true;
			}
		}
		
		
		// Convert the file information into a more user friendly format in the report
		public String cleanReportPath(String input, boolean isCleanReport){
			String retVal = input;
			if(isCleanReport){
				retVal=retVal.replace("sourcefiles.scriptoutput.", "");
				retVal=retVal.replace(".txt", "()");
				retVal=retVal.replace("..", "^*^"); // ^*^ is used as a temporary placeholder
				retVal=retVal.replace(".", "/");
				retVal=retVal.replace("^*^", ".");	// temporary placeholder is removed
				retVal=retVal.replace("./", "");
			
				// Now find the first "/" and replace everything before it.
				// This is used to remove the _copy from the output
				retVal = retVal.substring(retVal.indexOf("/")+1,retVal.length());
			}
			return retVal;
		}
	
		// Display the time to execute the program
		public String getTimeToRunProgram(Date startDate){
		    try { Thread.sleep(750); } catch(InterruptedException e) { /* ignore */ }  
		    Date currentTime = new Date();
		    long[] diff = getTimeDifference(startDate, currentTime);
		    return "Time to run Java compare process was: " + diff[0] +" day(s), " + diff[1] +"  hour(s), " + diff[2] +"  minute(s), " + diff[3] +"  second(s) and " + diff[4] + "  millisecond(s)\n";
		}
		
		
		private long[] getTimeDifference(Date d1, Date d2) {
	        long[] result = new long[5];
	        Calendar cal = Calendar.getInstance();
	        cal.setTimeZone(TimeZone.getTimeZone("UTC"));
	        cal.setTime(d1);

	        long t1 = cal.getTimeInMillis();
	        cal.setTime(d2);

	        long diff = Math.abs(cal.getTimeInMillis() - t1);
	        final int ONE_DAY = 1000 * 60 * 60 * 24;
	        final int ONE_HOUR = ONE_DAY / 24;
	        final int ONE_MINUTE = ONE_HOUR / 60;
	        final int ONE_SECOND = ONE_MINUTE / 60;

	        long d = diff / ONE_DAY;
	        diff %= ONE_DAY;

	        long h = diff / ONE_HOUR;
	        diff %= ONE_HOUR;

	        long m = diff / ONE_MINUTE;
	        diff %= ONE_MINUTE;

	        long s = diff / ONE_SECOND;
	        long ms = diff % ONE_SECOND;
	        result[0] = d;
	        result[1] = h;
	        result[2] = m;
	        result[3] = s;
	        result[4] = ms;

	        return result;
	    }
}
